#include "test_utilities.hpp"
#include "../system.hpp"
#include "system_test.hpp"

using std::cout;
using std::endl;

namespace systemTest {

const ID DUMMY_GAME_ID = 500;
const ID DUMMY_COMPANY_ID = 1;
const ID INVALID_COMPANY_ID = -1;
const int DUMMY_RATE = 5;
const int NUM_OF_COMPANIES = 100;

void testCreate();
void testAddGame();
void testRemoveGame();
void testMergCompanies();
void testGetGameCompany();
void testGetMinIdGameOfRate();

void run_system_tests() {
	RUN_TEST(testCreate);
    RUN_TEST(testAddGame);
	RUN_TEST(testRemoveGame);
	RUN_TEST(testMergCompanies);
	RUN_TEST(testGetGameCompany);
	RUN_TEST(testGetMinIdGameOfRate);
}

void testCreate() {
	ASSERT_NO_THROW(System(NUM_OF_COMPANIES));
}

/**
 * Scenarios:
 * add game1 with invalid company id - error
 * TODO: merge companies 2->1, add game1 with company 2 - error
 * 
 * add game1 with company 1
 * add game1 with company 1 - error
 * add game1 with company 3 - error
 * 
 * add 100 games with company 3
 * add 100 games with different companies.
 * 
 */
void testAddGame() {
	System system(NUM_OF_COMPANIES);
	const int gamesAmount = 100;
    
    ASSERT_THROWS(FailureException, system.addGame(DUMMY_GAME_ID, INVALID_COMPANY_ID, DUMMY_RATE));
    ASSERT_NO_THROW(system.addGame(DUMMY_GAME_ID, DUMMY_COMPANY_ID, DUMMY_RATE));
    ASSERT_THROWS(FailureException, system.addGame(DUMMY_GAME_ID, DUMMY_COMPANY_ID, DUMMY_RATE));
    ASSERT_THROWS(FailureException, system.addGame(DUMMY_GAME_ID, DUMMY_COMPANY_ID+2, DUMMY_RATE));
      
	for (ID id = 0; id < gamesAmount; ++id) {
		ASSERT_NO_THROW(system.addGame(id, DUMMY_COMPANY_ID, DUMMY_RATE));
	}

	for (ID i = gamesAmount; i < gamesAmount*2; ++i) {
		ASSERT_NO_THROW(system.addGame(i, i%NUM_OF_COMPANIES+1, i));
	}

}
/**
 * Scenarios
 * remove game1 - error
 * add game1
 * remove game2 - error|
 * remove game1
 * incrementally add and remove 100 games
 */
void testRemoveGame() {
	System system(NUM_OF_COMPANIES);
   
    ASSERT_THROWS(FailureException, system.removeGame(DUMMY_GAME_ID));
       
    ASSERT_NO_THROW(system.addGame(DUMMY_GAME_ID, DUMMY_COMPANY_ID, DUMMY_RATE));
    ASSERT_THROWS(FailureException, system.removeGame(DUMMY_GAME_ID+1));
    ASSERT_NO_THROW(system.removeGame(DUMMY_GAME_ID));
    
    for (int i = 1; i <= 101; i+=10){
      for (int j = 0; j < i; ++j){
          ASSERT_NO_THROW(system.addGame(j, j%NUM_OF_COMPANIES+1, j));
      }
      for (int j = 0; j < i; ++j){
          ASSERT_NO_THROW(system.removeGame(j));
      }
  }  
}

void testMergCompanies(){
	System system(NUM_OF_COMPANIES);

	ASSERT_THROWS(FailureException, system.mergeCompanies(NUM_OF_COMPANIES + 1, 1));
	ASSERT_THROWS(FailureException, system.mergeCompanies(0, 1));
	ASSERT_THROWS(FailureException, system.mergeCompanies(0, NUM_OF_COMPANIES + 1));

	for (int j = 2; j < NUM_OF_COMPANIES; j += 2){
		ASSERT_NO_THROW(system.addGame(DUMMY_GAME_ID + j - 1, j - 1, DUMMY_RATE));
		ASSERT_NO_THROW(system.mergeCompanies(j, j - 1));
		ASSERT_THROWS(FailureException,
			system.mergeCompanies(j - 1, NUM_OF_COMPANIES + 1));
		ASSERT_THROWS(FailureException,
			system.mergeCompanies(j - 1, NUM_OF_COMPANIES));
		ASSERT_EQUALS(j, system.getGameCompany(DUMMY_GAME_ID + j - 1));
	}

	for (int j = 4; j < NUM_OF_COMPANIES; j += 4){
		ASSERT_NO_THROW(system.mergeCompanies(j - 2, j));
		ASSERT_THROWS(FailureException,
			system.mergeCompanies(j, NUM_OF_COMPANIES + 1));
		ASSERT_THROWS(FailureException,
			system.mergeCompanies(j, NUM_OF_COMPANIES));
		ASSERT_EQUALS(j - 2, system.getGameCompany(DUMMY_GAME_ID + j - 1));
		ASSERT_EQUALS(j - 2, system.getGameCompany(DUMMY_GAME_ID + j - 3));
	}
}

void testGetGameCompany(){
	System system(NUM_OF_COMPANIES);

	ASSERT_THROWS(FailureException, system.getGameCompany(DUMMY_GAME_ID));
	ASSERT_NO_THROW(system.addGame(DUMMY_GAME_ID, 1, DUMMY_RATE));
	ASSERT_EQUALS(1, system.getGameCompany(DUMMY_GAME_ID));

	for (int j = 2; j <= NUM_OF_COMPANIES; ++j){
		ASSERT_NO_THROW(system.mergeCompanies(j, j - 1));
		ASSERT_EQUALS(j, system.getGameCompany(DUMMY_GAME_ID));
	}
	
}

void testGetMinIdGameOfRate(){
    
}

}
